// 自定义MyPromise函数模块
(function () {
    const PENDING = 'pending';
    const RESOLVED = 'resolved';
    const REJECTED = 'rejected';

    /**
     * MyPromise构造函数
     * @param excutor: 同步执行器
     * @constructor
     */
    function MyPromise(excutor) {
      this.status = PENDING; // promise状态属性
      this.data = undefined; // 存储结果数据的属性
      this.callbacks = []; // 如果在MyPromise执行完之前指定了回调，此时length>0,每个元素的结构:{onResolved(){}, onRejected(){}}
      const self = this;

      function resolve(value) {
        // 只能由pending->resolved或者rejected，且只能改一次
        if (self.status !== PENDING) {
          return
        }
        self.status = RESOLVED;
        self.data = value;
        if (self.callbacks.length) {
          self.callbacks.forEach(callbacksObj => {
            // 异步执行成功回调
            setTimeout(() => {
              callbacksObj.onResolved(value)
            })
          })
        }
      }

      function reject(reason) {
        // 只能由pending->resolved或者rejected，且只能改一次
        if (self.status !== PENDING) {
          return
        }
        self.status = REJECTED;
        self.data = reason;
        if (self.callbacks.length) {
          self.callbacks.forEach(callbacksObj => {
            // 异步执行成功回调
            setTimeout(() => {
              callbacksObj.onRejected(reason)
            })
          })
        }
      }

      // 立即同步执行executor,如果引发异常，则抛出，转为rejected状态
      try {
        excutor(resolve, reject)
      } catch (e) {
        reject(e)
      }
    }

    /**
     * then
     * @param onResolved
     * @param onRejected
     * @return MyPromise
     */
    MyPromise.prototype.then = function (onResolved, onRejected) {
      // 成功值传递
      onResolved = typeof onResolved === 'function' ? onResolved : value => value;
      // 实现异常穿透
      onRejected = typeof onRejected === 'function' ? onRejected : reason => {
        throw reason
      };
      const self = this;
      // then的返回值是一个Promise, 它的执行状态由onResolved/onRejected执行结果决定
      return new MyPromise((resolve, reject) => {
        // 调用指定回调函数，根据执行结果，改变return的promise的状态
        function handle(callback) {
          // 如果promise执行成功/失败，在执行回调的时候会有3种情况
          // 1. 回调时引发异常，此时返回值promise会变成rejected
          try {
            // 2. 回调返回的promise执行成功，返回值也是一个promise
            const result = callback(self.data);
            if (result instanceof MyPromise) {
              result.then(resolve, reject)
            } else {
              // 回调返回一个普通的值
              resolve(result);
            }
          } catch (e) {
            reject(e)
          }
        }

        if (self.status === PENDING) {
          // 假设当前状态还是pending
          self.callbacks.push({
            onResolved() {
              handle(onResolved)
            },
            onRejected() {
              handle(onRejected)
            }
          })
        } else if (self.status === RESOLVED) {
          setTimeout(() => {
            handle(onResolved)
          })
        } else {
          setTimeout(() => {
            handle(onRejected)
          })
        }
      })
    };
    /**
     * catch
     * @param onRejected
     */
    MyPromise.prototype.catch = function (onRejected) {
      return this.then(undefined, onRejected);
    };
    /**
     * resolve
     * @param value
     * @return {MyPromise}
     */
    MyPromise.resolve = function (value) {
      return new MyPromise((resolve, reject) => {
        if (value instanceof MyPromise) {
          value.then(resolve, reject)
        } else {
          // 普通值
          resolve(value)
        }
      })
    };
    /**
     * reject
     * @param reason
     * @return {MyPromise}
     */
    MyPromise.reject = function (reason) {
      // 返回一个失败的promise
      return new MyPromise(((resolve, reject) => {
        reject(reason)
      }))
    };
    /**
     * MyPromise.all
     * @param promises
     * @return {MyPromise}
     */
    MyPromise.all = function (promises) {
      let values = new Array(promises.length); // 创建一个数组存储所有promise成功的值
      let count = 0; // 成功的promise个数
      return new MyPromise((resolve, reject) => {
        promises.forEach((p, index) => {
          // 这里加MyPromise.resolve是防止p不一定是个Promise，而是个普通值
          MyPromise.resolve(p).then(value => {
            count++; // 又成功了1个
            values[index] = value;  // 每个promise对应的value，位置要一致
            if (count === promises.length) {
              // 所有的promise执行完毕
              resolve(values)
            }
          }, reason => {
            reject(reason); // 失败了一个直接返回
          })
        })
      })
    };
    /**
     * MyPromise.race
     * @param promises
     * @return {MyPromise}
     */
    MyPromise.race = function (promises) {
      return new MyPromise((resolve, reject) => {
        promises.forEach((p) => {
          MyPromise.resolve(p).then(value => {
            resolve(value)
          }, reason => {
            reject(reason); // 失败了一个直接返回
          })
        })
      })
    };

    /**
     * resolveDelay
     * @param value {MyPromise|Number|String|Object}
     * @param delay {Number}
     * @return {MyPromise}
     */
    MyPromise.resolveDelay = function (value, delay) {
      return new MyPromise((resolve, reject) => {
        setTimeout(() => {
          // 如果是一个promise
          if (value instanceof MyPromise) {
            value.then(resolve, reject)
          } else {
            resolve(value)
          }
        }, delay)
      })
    };

    /**
     * resolveDelay
     * @param value {MyPromise|Number|String|Object}
     * @param delay {Number}
     * @return {MyPromise}
     */
    MyPromise.rejectDelay = function (value, delay) {
      return new MyPromise((resolve, reject) => {
        setTimeout(() => {
          reject(value)
        }, delay)
      })
    };

    // 向外暴露MyPromise
    window.MyPromise = MyPromise
  }
)(window);
